<template>
  <div class="we-container">
    <!-- 固定工具栏 -->
    <Toolbar
      class="we-toolbar"
      :editor="editorRef"
      :mode="'default'"
      :defaultConfig="toolbarConfig"
    />

    <!-- 固定编辑器 -->
    <Editor
      class="we-editor"
      v-model="innerValue"
      :mode="'default'"
      :defaultConfig="editorConfig"
      @onCreated="handleCreated"
      @onChange="handleChange"
      @onDestroyed="handleDestroyed"
    />
  </div>
</template>

<script setup lang="ts">
import { computed, shallowRef, onBeforeUnmount, nextTick } from 'vue'
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

/**
 * 唯一对外接口：v-model（HTML 字符串）
 * 其他配置都已在本组件内部“写死”，父组件无需传入。
 */
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{
  (e: 'update:modelValue', v: string): void
  (e: 'change', v: { html: string; text: string; editor: IDomEditor }): void
}>()

/** 编辑器实例（必须 shallowRef） */
const editorRef = shallowRef<IDomEditor | null>(null)

/** 固定：工具栏白名单（按需裁剪） */
const toolbarConfig: Partial<IToolbarConfig> = {
  toolbarKeys: [
    'headerSelect',
    'bold',
    'italic',
    'underline',
    'through',
    'color',
    'bulletedList',
    'numberedList',
    'todo',
    'insertLink',
    'blockquote',
    'code',
    'insertTable',
    'insertImage',
    'divider',
    'undo',
    'redo'
  ] as any
}

/** 固定：编辑器配置（占位符、只读=z false、zIndex、图片上传、最大字数等） */
const editorConfig: IEditorConfig = {
  placeholder: '请输入内容…',
  readOnly: false, // 默认可编辑；如需切换用 setReadOnly()
  scroll: true,
  zIndex: 3000, // 与弹窗叠放时较安全
  MENU_CONF: {
    // 图片上传：默认转 base64 图片url，便于无后端也能用；有后端可改为自定义上传
    uploadImage: {
      async customUpload(file: File, insertFn: (url: string) => void) {
        /**
         * 真正传给后端
         */
        const b64 = await fileToBase64(file)
        insertFn(b64) // 直接插入 base64
      }
    }
  }
  // 如需固定最大字数（示例给 10000），可解开下面注释：
  // maxLength: 100
}

/** v-model 内部计算属性 */
const innerValue = computed({
  get: () => props.modelValue || '',
  set: (v) => emit('update:modelValue', v)
})

/** 编辑器创建 */
const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor
}

/** 内容变化（可在这里做统一约束与外抛） */
const handleChange = (editor: IDomEditor) => {
  emit('change', { html: editor.getHtml(), text: editor.getText(), editor })
}

/** 销毁回调 */
function handleDestroyed() {
  // 这里通常无需额外动作
}

/** 组件卸载时确保销毁实例，避免内存泄漏 */
onBeforeUnmount(() => {
  const ed = editorRef.value
  if (ed) {
    ed.destroy()
    editorRef.value = null
  }
})

/** 工具函数：File -> base64 ： 文件/图片转 base64 url地址*/
function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(String(reader.result))
    reader.onerror = reject
    reader.readAsDataURL(file)
  })
}

/** —— 对外暴露常用方法（无需 props 即可在父组件里控制） —— */
async function focus() {
  await nextTick()
  editorRef.value?.focus()
}
async function blur() {
  await nextTick()
  editorRef.value?.blur()
}
function getHtml() {
  return editorRef.value?.getHtml() || ''
}
function setHtml(html: string) {
  editorRef.value?.setHtml(html)
}
function setReadOnly(isReadonly: boolean) {
  const ed = editorRef.value
  if (!ed) return
  isReadonly ? ed.disable() : ed.enable()
}

defineExpose({ focus, blur, getHtml, setHtml, setReadOnly })
</script>

<style scoped>
/* 容器固定样式（配置“写死”在组件里） */
.we-container {
  display: flex;
  flex-direction: column;
  border: 1px solid #e5e6eb;
  border-radius: 8px;
  background: #fff;
  overflow: hidden;
  /* 固定高度；若需全局统一改，可用:deep(.we-container) 覆盖 */
  height: 420px;
}

/* 工具栏样式 */
.we-toolbar {
  border-bottom: 1px solid #eee;
}

/* 编辑区域占满剩余空间 */
.we-editor {
  flex: 1;
}
</style>
